/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package lintulaskenta.servlet.havainnointi;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.TreeMap;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import lintulaskenta.entity.Havaintopiste;
import lintulaskenta.entity.Pistevuosi;
import lintulaskenta.entity.Reitti;
import lintulaskenta.pulautin.SyotteenTarkastaja;
import lintulaskenta.rekisteri.Rekisteri;

/**
 *
 * @author Anna
 */
public class HavaintopisteServlet extends HttpServlet {

    private TreeMap<String, Object> pisteenTila;
    private HttpSession session;
    private SyotteenTarkastaja tarkastaja = new SyotteenTarkastaja();
    private Rekisteri rekisteri = new Rekisteri();
    private String virhe = "";
    private Pistevuosi p;

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        request.setCharacterEncoding("UTF-8");

        virhe = "";
        session = request.getSession(false);
        p = (Pistevuosi) request.getSession().getAttribute("piste");
        pisteenTila = (TreeMap<String, Object>) session.getAttribute("pisteenTila");
        TreeMap<String, Object> yleinenTila = (TreeMap<String, Object>) session.getAttribute("yleinenTila");

        // Etsitään kannasta pisteitä koordinaateilla.

        if (request.getParameter("search") != null) {
            if (tarkistaSyotteenKoordinaatit(request.getParameter("pohjoiskoordinaatti"), request.getParameter("itakoordinaatti"))) {
                int pohjoisk = Integer.parseInt(request.getParameter("pohjoiskoordinaatti"));
                int itak = Integer.parseInt(request.getParameter("itakoordinaatti"));
                if (itak != 0 || pohjoisk != 0) {
                    if (!sisaltaakoReittiKoordinaatit(itak, pohjoisk)) {
                        List<Havaintopiste> havaintopisteet = (List<Havaintopiste>) rekisteri.getResultList("select u from Havaintopiste u where u.pohjoiskoordinaatti = " + pohjoisk + "and u.itakoordinaatti = " + itak, Havaintopiste.class);
                        session.setAttribute("havaintopisteet", havaintopisteet);
                    }
                } else {
                    session.setAttribute("havaintopisteet", new ArrayList<Havaintopiste>());
                }
                pisteenTila.put("pohjoiskoordinaatti", pohjoisk);
                pisteenTila.put("itakoordinaatti", itak);
            }
        }


        // Lisätään pistevuoteen tietokannassa oleva havaintopiste.
        if (request.getParameter("attach") != null) {
            int index = Integer.parseInt(request.getParameter("havaintopiste"));
            List<Havaintopiste> havaintopisteet = (List<Havaintopiste>) session.getAttribute("havaintopisteet");
            if (havaintopisteet.size() > index) {
                Reitti reitti = (Reitti) session.getAttribute("reitti");
                Havaintopiste uusi = havaintopisteet.get(index);
                reitti.addHavaintopiste(uusi);
                p.setHavaintopiste(uusi);
            }
            session.removeAttribute("havaintopisteet");
            pisteenTila.remove("havaintopiste");
        }


        // Luodaan uusi havaintopiste syötteen koordinaateilla ja lisätään se pistevuoteen.
        if (request.getParameter("create") != null) {
            tallennaUusiHavaintopiste();
            session.removeAttribute("havaintopisteet");
            pisteenTila.remove("havaintopiste");
        }

        // Vaihdetaan havaintopisteen tilaksi 'update' eli ollaan muokkaamassa olemassaolevan havaintopisteen koordinaatteja.
        if (request.getParameter("update") != null) {
            pisteenTila.put("havaintopiste", "update");
            session.removeAttribute("havaintopisteet");
        }

        // Vaihdetaan havaintopisteen tilaksi 'change' eli vaihdetaan pistevuoden havaintopistettä. Mahdollista vain, jos pistevuodelle 
        // ollaan ensimmäistä kertaa lisäämässä havaintopistettä.
        if (request.getParameter("change") != null) {
            pisteenTila.put("havaintopiste", "change");
            session.removeAttribute("havaintopisteet");
        }

        // Havaintopisteen koordinaatit muutetaan syötettä vastaaviksi, jos reitin millään pistevuoden havaintopisteellä
        // ei ole vastaavia koordinaatteja, ja kannassa ei ole havaintopistettä, jolla olisi vastaavat koordinaatit.
        if (request.getParameter("save") != null) {
            if (tarkistaSyotteenKoordinaatit(request.getParameter("pohjoiskoordinaatti"), request.getParameter("itakoordinaatti"))) {
                tallennaHavaintopisteenUudetKoordinaatit(p.getHavaintopiste(), Integer.parseInt(request.getParameter("itakoordinaatti")), Integer.parseInt(request.getParameter("pohjoiskoordinaatti")));
            }
        }

        // Peruutetaan havaintopisteen lisääminen, muokkaaminen jne.
        if (request.getParameter("cancel") != null) {
            peruuta();
        }

        response.sendRedirect(yleinenTila.get("url") + virhe + "#pisteet");
    }

    private boolean tarkistaSyotteenKoordinaatit(String pohjoisk, String itak) {
        if (pohjoisk.isEmpty() || itak.isEmpty()) {
            virhe = "?virhe=Anna koordinaatit!";
            return false;
        }
        if (!tarkastaja.isANumber(itak) || !tarkastaja.isANumber(pohjoisk)) {
            virhe = "?virhe=Koordinaattien tulee sisältää vain numeroita!";
            return false;
        }
        return true;
    }

    // Tarkistetaan, ettei reitin millään havaintopisteellä ole jo vastaavia koordinaatteja.
    private boolean sisaltaakoReittiKoordinaatit(int itak, int pohjoisk) {

        TreeMap<Integer, Pistevuosi> pisteet = (TreeMap<Integer, Pistevuosi>) session.getAttribute("pisteet");
        for (Entry e : pisteet.entrySet()) {
            Pistevuosi pv = (Pistevuosi) e.getValue();
            if (pv.getHavaintopiste() != null) {
                if (pv.getHavaintopiste().getItakoordinaatti() == itak && pv.getHavaintopiste().getPohjoiskoordinaatti() == pohjoisk) {
                    virhe = "?virhe=Reitin jollain pisteellä on jo kyseiset koordinaatit!";
                    return true;
                }
            }
        }
        return false;
    }

    private boolean sisaltaakoKantaKoordinaatit(int itak, int pohjoisk) {
        List<Havaintopiste> havaintopisteet = (List<Havaintopiste>) rekisteri.getResultList("select u from Havaintopiste u where u.pohjoiskoordinaatti = " + pohjoisk + "and u.itakoordinaatti = " + itak, Havaintopiste.class);
        if (havaintopisteet.isEmpty()) {
            return false;
        }
        virhe = "?virhe=Havaintopiste vastaavilla koordinaateilla on jo olemassa!";
        return true;
    }

    private void peruuta() {
        pisteenTila.put("pohjoiskoordinaatti", 0);
        pisteenTila.put("itakoordinaatti", 0);
        pisteenTila.remove("havaintopiste");
        session.removeAttribute("havaintopisteet");
    }

    private void tallennaHavaintopisteenUudetKoordinaatit(Havaintopiste h, int itak, int pohjoisk) {
        if ((itak == 0 && pohjoisk == 0) || (!sisaltaakoReittiKoordinaatit(itak, pohjoisk) && !sisaltaakoKantaKoordinaatit(itak, pohjoisk))) {
            h.setItakoordinaatti(itak);
            h.setPohjoiskoordinaatti(pohjoisk);
            pisteenTila.remove("havaintopiste");
        }
    }

    private void tallennaUusiHavaintopiste() {
        Havaintopiste h = new Havaintopiste();
        h.addReitti((Reitti) session.getAttribute("reitti"));
        h.setItakoordinaatti((Integer) pisteenTila.get("itakoordinaatti"));
        h.setPohjoiskoordinaatti((Integer) pisteenTila.get("pohjoiskoordinaatti"));
        p.setHavaintopiste(h);
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /** 
     * Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Returns a short description of the servlet.
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}
